package com.ml4ai.backend.services.boot;

import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.ml4ai.backend.consts.UserConstants;
import com.ml4ai.backend.dto.UserDTO;
import com.ml4ai.backend.services.DbMapService;
import com.ml4ai.backend.services.UserService;
import com.ml4ai.core.stack.elasticsearch.BoolBuilderCreator;
import com.ml4ai.core.stack.elasticsearch.ElasticSearchAgent;
import com.ml4ai.core.stack.mq.RabbitMQAgent;
import com.ml4ai.core.stack.utils.GsonUtil;
import com.ml4ai.core.stack.utils.Toolkit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by leecheng on 2018/11/25.
 */
@Component
@Slf4j
public class CommandExecutor implements CommandLineRunner {

    @Value("${elasticsearch.servers}")
    private String esServers;

    @Value("${elasticsearch.cluster}")
    private String cluster;

    @Value("${rabbitmq.host}")
    private String rabbitmqHost;

    @Value("${rabbitmq.port}")
    private Integer rabbitmqPort;

    @Value("${rabbitmq.username}")
    private String rabbitmqUsername;

    @Value("${rabbitmq.password}")
    private String rabbitmqPassword;

    @Value("${rabbitmq.virtualHost}")
    private String rabbitmqVirtualHost;

    @Autowired
    private UserService userService;

    @Autowired
    DbMapService dbMapService;

    private ElasticSearchAgent elasticsearch;
    private RabbitMQAgent rabbitMQAgent;
    private Gson gson;
    private JsonParser jsonParser;

    @PostConstruct
    public void init() {
        elasticsearch = ElasticSearchAgent.builder().esServers(esServers).esCluster(cluster).build();
        rabbitMQAgent = RabbitMQAgent.builder().host(rabbitmqHost).port(rabbitmqPort).user(rabbitmqUsername).password(rabbitmqPassword).vHost(rabbitmqVirtualHost).build();
        jsonParser = new JsonParser();
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.serializeNulls();
        gsonBuilder.setDateFormat("yyyy-MM-dd");
        gson = gsonBuilder.create();
    }

    @Override
    public void run(String... strings) throws Exception {
        rabbitMQAgent.declareQueue("command",true,false,false,null);
        rabbitMQAgent.consumeText("command", 1, data -> {

            Map<String, Object> response = new LinkedHashMap<>();
            response.put("code", "404");
            response.put("msg", "未处理");
            response.put("data", "");

            JsonObject json = jsonParser.parse(data).getAsJsonObject();
            String queue = GsonUtil.getFieldAsString(json, "queue");

            try {
                Map<String, String> tokenStoreMap = dbMapService.generateLocalMapWrapper(UserConstants.TOKEN_USER_MAP);

                String command = json.get("command").getAsString();
                String token;
                String username;
                String password;
                Integer start;
                Integer size;
                SearchRequestBuilder searchRequestBuilder;
                Map<String, Object> parameter;

                switch (command) {
                    case "loadAbstracts":
                        start = GsonUtil.getFieldAsInt(json, "start");
                        size = GsonUtil.getFieldAsInt(json, "size");
                        parameter = gson.fromJson(json.get("parameter"), Map.class);
                        searchRequestBuilder = elasticsearch.getClient().prepareSearch("app-contents").setTypes("default");
                        SearchResponse searchResponse = searchRequestBuilder.setQuery(BoolBuilderCreator.createBoolQueryBuilder(parameter)).setFrom(start).setSize(size).get();
                        List<Map<String, Object>> list = Lists.newArrayList(searchResponse.getHits()).stream().map(SearchHit::getSourceAsMap).collect(Collectors.toList());
                        response.put("code", "200");
                        response.put("msg", "摘取成功");
                        response.put("data", list);
                        break;
                    case "publicContent":
                        token = GsonUtil.getFieldAsString(json, "token");
                        if (StringUtils.isNotEmpty(token)) {
                            username = tokenStoreMap.get(token);
                            parameter = gson.fromJson(json.get("parameter"), Map.class);
                            parameter.put("createUser", username);
                            elasticsearch.getClient().prepareIndex("app-contents", "default").setSource(parameter).get();
                            response.put("code", "200");
                            response.put("msg", "发布成功");
                            response.put("data", "");
                        } else {
                            response.put("code", "500");
                            response.put("msg", "发布失败，没有登录");
                            response.put("data", "");
                        }
                        break;
                    case "login":
                        username = GsonUtil.getFieldAsString(json, "username");
                        password = GsonUtil.getFieldAsString(json, "password");
                        queue = GsonUtil.getFieldAsString(json, "queue");
                        if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
                            UserDTO user = userService.findByLogin(username);
                            if (password.equals(Toolkit.MD5.getMessageDigest(user.getPassword()))) {
                                String tokenKey = Toolkit.StringHelper.uuid();
                                tokenStoreMap.put(tokenKey, username);
                                response.put("code", "200");
                                response.put("msg", "认证成功!");
                                response.put("data", tokenKey);
                                break;
                            }
                        }
                        response.put("code", "401");
                        response.put("msg", "认证失败");
                        response.put("data", "");
                        break;
                    default:
                        response.put("code", "404");
                        response.put("msg", "找不到命令");
                        response.put("data", "");
                        break;
                }
                rabbitMQAgent.produceText("", queue, gson.toJson(response), false);
            } catch (Exception e) {
                log.error("错误", e);
                response.put("code", "500");
                response.put("msg", "发生错误！");
                response.put("data", "");
                rabbitMQAgent.produceText("", queue, gson.toJson(response), false);
            }
            return true;
        });
    }


}
